﻿using NotificationsExtensions.ToastContent;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Notifications;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Threading;
using System.Threading.Tasks;
using TT.CIT.Common;
using Windows.Web.Http.Filters;
using Windows.Web.Http;
using Windows.Web.Http.Headers;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Windows.Storage.Streams;
using Windows.Security.Cryptography;
using System.Net;
using System.Globalization;
using Windows.UI.Xaml.Media.Imaging;
using Windows.Graphics.Imaging;
using Windows.UI;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=391641

namespace TT.CIT
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page, IDisposable
    {
        private NavigationHelper navigationHelper;
        private ObservableDictionary defaultViewModel = new ObservableDictionary();

        DispatcherTimer timer = null;
        DispatcherTimer timer2 = null;
        private HttpBaseProtocolFilter filter;
        private HttpClient httpClient;
        private CancellationTokenSource cts;
        private Common.TTSettings config = null;
        private DateTime Relogio;


        public MainPage()
        {
            this.InitializeComponent();
            this.NavigationCacheMode = NavigationCacheMode.Disabled;

            this.navigationHelper = new NavigationHelper(this);
            this.navigationHelper.LoadState += this.NavigationHelper_LoadState;
            this.navigationHelper.SaveState += this.NavigationHelper_SaveState;
        }

        /// <summary>
        /// Gets the <see cref="NavigationHelper"/> associated with this <see cref="Page"/>.
        /// </summary>
        public NavigationHelper NavigationHelper
        {
            get { return this.navigationHelper; }
        }

        /// <summary>
        /// Gets the view model for this <see cref="Page"/>.
        /// This can be changed to a strongly typed view model.
        /// </summary>
        public ObservableDictionary DefaultViewModel
        {
            get { return this.defaultViewModel; }
        }

        /// <summary>
        /// Populates the page with content passed during navigation.  Any saved state is also
        /// provided when recreating a page from a prior session.
        /// </summary>
        /// <param name="sender">
        /// The source of the event; typically <see cref="NavigationHelper"/>
        /// </param>
        /// <param name="e">Event data that provides both the navigation parameter passed to
        /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested and
        /// a dictionary of state preserved by this page during an earlier
        /// session.  The state will be null the first time a page is visited.</param>
        private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
        {
        }

        /// <summary>
        /// Preserves state associated with this page in case the application is suspended or the
        /// page is discarded from the navigation cache.  Values must conform to the serialization
        /// requirements of <see cref="SuspensionManager.SessionState"/>.
        /// </summary>
        /// <param name="sender">The source of the event; typically <see cref="NavigationHelper"/></param>
        /// <param name="e">Event data that provides an empty dictionary to be populated with
        /// serializable state.</param>
        private void NavigationHelper_SaveState(object sender, SaveStateEventArgs e)
        {
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  The Parameter
        /// property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            this.navigationHelper.OnNavigatedTo(e);

            timer = new DispatcherTimer();
            timer2 = new DispatcherTimer();

            config = new TTSettings();
            filter = new HttpBaseProtocolFilter();
            httpClient = new Windows.Web.Http.HttpClient(filter);
            cts = new CancellationTokenSource();

            Relogio = new DateTime();
            SincronizaRelogio();

            //Carrega o usuário padrão
            if (config != null)
            {
                if (config.UsuarioSetting != string.Empty)
                {
                    Usuario.Text = config.UsuarioSetting;
                }

                if (config.SenhaSetting != string.Empty)
                {
                    Senha.Password = config.SenhaSetting;
                }

                if (config.FotoSetting != null)
                {
                    LoadImage();
                }

                if (config.UltimoCheckin != null)
                {
                    UltimoCheckin.Text = "Último Checkin: " + config.UltimoCheckin;
                }
                else
                {
                    UltimoCheckin.Text = "Último Checkin: Nenhum";
                }
            }

            if (e.Parameter != null && e.NavigationMode == NavigationMode.New)
            {
                //Log.Text = e.Parameter.ToString();

                if (e.Parameter.ToString() == "checkin")
                {
                    //Executa o método de checkin pelo NFC, se estiver habilitado
                    if (config.NFCSetting)
                    {
                        Pre_checkin(true);
                    }
                    else
                    {
                        NotifyUser("Checkin por tags NFC desabilitada. Habilite esta configuração se quiser usar esta função.", NotifyType.ErrorMessage);
                    }
                }
            }

            //if (NavigationContext.QueryString.TryGetValue("ms_nfp_launchargs", out parameter))
            //{
            //    MessageBox.Show("Congratulation\nYou launch application with a NFC tag.\nParamaters : " + parameter);
            //    NavigationContext.QueryString.Remove("ms_nfp_launchargs");
            //}
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            this.navigationHelper.OnNavigatedFrom(e);

            // If the navigation is external to the app do not clean up.
            // This can occur on Phone when suspending the app.
            if (e.NavigationMode == NavigationMode.Forward && e.Uri == null)
            {
                return;
            }
            Dispose();
            //App.Current.Exit();
        }

        private void CommandBar_Opened(object sender, object e)
        {

        }

        private void AppBarButton_Click(object sender, RoutedEventArgs e)
        {
            Pre_checkin();
        }

        private void Pre_checkin(bool NFCCheckin = false)
        {
            //Salva os dados do usuário
            if (!string.IsNullOrEmpty(Usuario.Text) && !string.IsNullOrEmpty(Senha.Password))
            {
                config.UsuarioSetting = Usuario.Text.Replace(" ", "").ToLower();
                config.SenhaSetting = Senha.Password.Replace(" ", "");
                GetFoto();
                Checkin(NFCCheckin);
            }
            else
            {
                NotifyUser("Usuário e senha não configurados ainda.", NotifyType.ErrorMessage);
            }
        }

        public async void NotifyUser(string strMessage, NotifyType type)
        {
            await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                switch (type)
                {
                    case NotifyType.StatusMessage:
                        Retorno.Foreground = new SolidColorBrush(Color.FromArgb(255, 32, 189, 190));
                        //Retorno.Style = this.Resources["StatusStyle"] as Style;
                        break;
                    case NotifyType.ErrorMessage:
                        Retorno.Foreground = new SolidColorBrush(Color.FromArgb(255, 237, 25, 65));
                        //Retorno.Style = this.Resources["ErrorStyle"] as Style;
                        break;
                }
                Retorno.Text = strMessage;
            });
        }

        public enum NotifyType
        {
            StatusMessage,
            ErrorMessage
        };

        private void AppBarButton_Click_1(object sender, RoutedEventArgs e)
        {

        }

        private void Grid_Loaded(object sender, RoutedEventArgs e)
        {

        }

        private void SincronizaRelogio()
        {
            //Atualiza a data e a hora
            Data.Text = "";
            Hora.Text = "";

            Retorno.Text = "Sincronizando o relógio...";

            AtualizaRelogio();
        }

        /// <summary>
        /// Incrementa oa relógio a partir da hora do servidor
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer_Tick(object sender, object e)
        {
            this.Relogio = this.Relogio.AddSeconds(1);
            Hora.Text = this.Relogio.ToString("HH:mm:ss");
        }

        private void timer2_Tick(object sender, object e)
        {
            NotifyUser("", NotifyType.StatusMessage);
            timer2.Stop();
            timer2 = null;
        }


        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
        }

        /// <summary>
        /// Método que atualiza o relógio da aplicação com o do servidor do TT.
        /// </summary>
        private async void AtualizaRelogio()
        {
            DateTime retorno = DateTime.Now;
            string Url = "https://tt.ciandt.com/.net/index.ashx/GetClockDeviceInfo?_dc=1402665085408&deviceID=2&sessionID=0&selectedEmployee=0&selectedCandidate=0&selectedVacancy=0&dtFmt=d%2Fm%2FY&tmFmt=H%3Ai%3As&shTmFmt=H%3Ai&dtTmFmt=d%2Fm%2FY%20H%3Ai%3As&language=0";
            Uri urlTime;

            try
            {
                if (Helpers.TryGetUri(Url, out urlTime))
                {
                    HttpResponseMessage response = new HttpResponseMessage();

                    filter.CacheControl.ReadBehavior = HttpCacheReadBehavior.MostRecent;
                    response = await httpClient.GetAsync(urlTime).AsTask(cts.Token);
                    response.EnsureSuccessStatusCode();
                    string responseText = await response.Content.ReadAsStringAsync();

                    if (responseText != string.Empty)
                    {
                        //var format = "yyyy-MM-dd HH:mm:ss"; // your datetime format
                        //var dateTimeConverter = new IsoDateTimeConverter { DateTimeFormat = format };
                        //var deserialized = JsonConvert.DeserializeObject<Model.Relogio>(responseText, dateTimeConverter);

                        int start = responseText.LastIndexOf("dtTimeEvent:");
                        int lengh = responseText.LastIndexOf(")") - responseText.LastIndexOf("dtTimeEvent:");
                        string dtEvent = responseText.Substring(start, lengh).Replace("new Date(", "").Replace("dtTimeEvent: ", "");

                        if (!string.IsNullOrEmpty(dtEvent))
                        {
                            string[] dados = dtEvent.Split(',');
                            retorno = new DateTime(int.Parse(dados[0]),
                                int.Parse(dados[1]),
                                int.Parse(dados[2]),
                                int.Parse(dados[3]),
                                int.Parse(dados[4]),
                                int.Parse(dados[5]));
                        }

                        Retorno.Text = "";
                    }
                }
            }
            catch (TaskCanceledException)
            {
            }
            catch (Exception e)
            {
                this.NotifyUser("Ocorreu um erro ao tentar sincronizar o relório com o servidor.", NotifyType.ErrorMessage);
            }

            //Ajusta o relógio
            this.Relogio = retorno;

            Data.Text = this.Relogio.ToString("dd/MM/yyyy");
            Hora.Text = this.Relogio.ToString("HH:mm:ss");

            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += timer_Tick;
            timer.Start();
        }

        /// <summary>
        /// Método que faz o download da foto do usuário logado
        /// </summary>
        public async void GetFoto()
        {
            byte[] foto = null;
            string Url = "https://people.cit.com.br/photos/{0}.jpg";
            Uri urlTime;

            try
            {
                if (config != null)
                {
                    Url = string.Format(Url, config.UsuarioSetting);

                    if (Helpers.TryGetUri(Url, out urlTime))
                    {
                        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, urlTime);

                        var handler = new System.Net.Http.HttpClientHandler { Credentials = new NetworkCredential(config.UsuarioSetting, config.SenhaSetting) };

                        System.Net.Http.HttpClient Client = new System.Net.Http.HttpClient(handler);
                        byte[] response = await Client.GetByteArrayAsync(urlTime);

                        //Stream to Bitmap
                        //Stream stream = await Client.GetStreamAsync(urlTime);
                        //var memStream = new MemoryStream();
                        //await stream.CopyToAsync(memStream);
                        //memStream.Position = 0;
                        //foto = new BitmapImage();
                        //foto.SetSource(memStream.AsRandomAccessStream());

                        if (response != null)
                        {
                            foto = response;
                        }
                    }
                }
            }
            catch (TaskCanceledException)
            {
            }
            catch (Exception e)
            {
            }

            if (foto != null)
            {
                if (config != null)
                {
                    config.FotoSetting = foto;
                    LoadImage();
                }
            }
        }

        /// <summary>
        /// Método que carrega a imagem na tela.
        /// </summary>
        public async void LoadImage()
        {
            try
            {
                if (config != null)
                {
                    if (config.FotoSetting != null)
                    {
                        updateImage(config.FotoSetting);
                    }
                }
            }
            catch (Exception e)
            {
                NotifyUser("Erro ao exibir a foto.", NotifyType.ErrorMessage);
            }
        }

        /// <summary>
        /// Método que carrega a imagem do byte[] para o Bitmap
        /// </summary>
        /// <param name="byteArray"></param>
        /// <returns></returns>
        public async void updateImage(byte[] byteArray)
        {
            MemoryStream stream = new MemoryStream(byteArray);
            var randomAccessStream = new MemoryRandomAccessStream(stream);
            BitmapImage bitmapImage = new BitmapImage();
            await bitmapImage.SetSourceAsync(randomAccessStream);
            Foto.ImageSource = bitmapImage;
        }

        /// <summary>
        /// Método que faz o checkin no TT.
        /// </summary>
        private async void Checkin(bool NFCCheckin = false)
        {
            string retorno = string.Empty;
            string Url = "https://tt.ciandt.com/.net/index.ashx/SaveTimmingEvent?deviceID=2&eventType=1&userName={0}&password={1}&cracha=&costCenter=&leave=&func=&sessionID=0&selectedEmployee=0&selectedCandidate=0&selectedVacancy=0&dtFmt=d%2Fm%2FY&tmFmt=H%3Ai%3As&shTmFmt=H%3Ai&dtTmFmt=d%2Fm%2FY%20H%3Ai%3As&language=0";
            Uri urlTime;

            this.NotifyUser("", NotifyType.StatusMessage);

            try
            {
                if (config != null)
                {
                    //Verifica se o checkin é pelo NFC e se faz menos de 1 minuto
                    //if (NFCCheckin)
                    //{
                    //    DateTime dttLastCheckin = new DateTime();

                    //    if (DateTime.TryParse(config.UltimoCheckin, out dttLastCheckin))
                    //    {
                    //        var dif = this.Relogio.Subtract(dttLastCheckin);
                    //        if (dif.Minutes <= 1)
                    //        {
                    //            NotifyUser("Você já realizou este checkin pelo NFC a menos de 1 minuto.", NotifyType.ErrorMessage);
                    //            return;
                    //        }
                    //    }
                    //}

                    Url = string.Format(Url, System.Net.WebUtility.UrlEncode(config.UsuarioSetting), System.Net.WebUtility.UrlEncode(config.SenhaSetting));

                    if (Helpers.TryGetUri(Url, out urlTime))
                    {
                        HttpResponseMessage response = new HttpResponseMessage();

                        filter.CacheControl.ReadBehavior = HttpCacheReadBehavior.MostRecent;

                        //httpClient.DefaultRequestHeaders.Add(new KeyValuePair<string, string>("ApWebDispatcher_in", "")); //Format: 6/15/2014 4:09:44 PM
                        //httpClient.DefaultRequestHeaders.Add(new KeyValuePair<string, string>("ApWebDispatcher_out", "")); //Format: 6/15/2014 4:09:44 PM
                        //httpClient.DefaultRequestHeaders.Add(new KeyValuePair<string, string>("timeF", "")); //Format: 2014-06-15 16:09:45.153
                        //httpClient.DefaultRequestHeaders.Add(new KeyValuePair<string, string>("timeI", "")); //format: 2014-06-15 16:09:45.153
                        httpClient.DefaultRequestHeaders.Cookie.Add(new HttpCookiePairHeaderValue("clockDeviceToken", "nHuH/qaEaN1TzYclwDbze2UcjZeQtjjudvHqcjFufA=="));

                        response = await httpClient.GetAsync(urlTime).AsTask(cts.Token);
                        response.EnsureSuccessStatusCode();
                        string responseText = await response.Content.ReadAsStringAsync();

                        if (responseText != string.Empty)
                        {
                            var deserialized = JsonConvert.DeserializeObject<Model.RetornoCheckin>(responseText);

                            if (deserialized.msg.msg.Contains("Server Error"))
                            {
                                this.NotifyUser(deserialized.msg.msg, NotifyType.ErrorMessage);
                            }
                            else
                            {
                                this.NotifyUser(deserialized.msg.msg, NotifyType.StatusMessage);
                                config.UltimoCheckin = this.Relogio.ToString("dd/MM/yyyy HH:mm:ss");
                            }
                        }
                    }
                }
            }
            catch (TaskCanceledException)
            {
            }
            catch (Exception e)
            {
                this.NotifyUser("Ocorreu um erro ao tentar realizar o apontamento no Time Tracking.", NotifyType.ErrorMessage);
            }

            if (config.UltimoCheckin != null)
            {
                UltimoCheckin.Text = "Último Checkin: " + config.UltimoCheckin;
            }
            else
            {
                UltimoCheckin.Text = "Último Checkin: Nenhum";
            }

            timer2 = new DispatcherTimer();
            timer2.Interval = TimeSpan.FromSeconds(10);
            timer2.Tick += timer2_Tick;
            timer2.Start();
        }

        private void AppBarButton_Click_2(object sender, RoutedEventArgs e)
        {
            //Botão Config
            this.Frame.Navigate(typeof(Configuracao));
        }

        private void Page_Unloaded(object sender, RoutedEventArgs e)
        {
        }

        public void Dispose()
        {
            if (config != null)
            {
                config = null;
            }

            if (timer != null)
            {
                timer.Stop();
                timer = null;
            }

            if (timer2 != null)
                timer2 = null;

            if (filter != null)
            {
                filter.Dispose();
            }

            if (httpClient != null)
            {
                httpClient.Dispose();
            }

            if (cts != null)
            {
                cts.Dispose();
                cts = null;
            }
        }
    }
}
